import * as Cesium from 'cesium';
import * as lodash from 'lodash';
// types
import type { IArea, ICameraOrientation, IPositionLngLatHeight, ICircle } from './index.d';
// apis
// hooks
// utils
// stores
// configs
import roadJson from '../../assets/json/road.json';
import cameraJson from '../../assets/json/camera.json';
import townJson from '../../assets/json/town.json';
// components
// emits
// refs
// computed
// methods
// watch
import roadImage from '../../assets/image/road.png';
import map_icon_camera from '../../assets/image/map_icon_camera.png';

// geojson数据的某个属性
interface IProperty {
  [key: string]: any;
}
// 函数传入数据
interface IProps {
  dom: string;
  initMapCallback?: () => void;
  onClickPoint?: (property: IProperty | IProperty[]) => void;
  onClickArea?: (property: IProperty | IProperty[]) => void;
}

export default class BaseMap {
  private dom: string; // dom容器
  private initMapCallback?: () => void; // 初始化地图回调函数
  private onClickPoint?: (property: IProperty | IProperty[]) => void; // 点击点位回调函数
  private onClickArea?: (property: IProperty | IProperty[]) => void; // 点击区域回调函数

  private innerImageryLayerDataSource?: Map<string, Cesium.ImageryLayer>; // 内部数据源 - 图层
  private innerPointDataSource?: Map<string, Cesium.Entity>; // 内部数据源 - 内部（撒点）
  private innerAreaDataSource?: Map<string, Cesium.Entity>; // 内部数据源 - 内部（区域）

  private innerCircleDataSource?: Map<string, Cesium.Entity>; // 内部数据源 - 内部（圈）

  viewer?: Cesium.Viewer; // viewer实例

  constructor({ dom, initMapCallback, onClickPoint, onClickArea }: IProps) {
    this.dom = dom;
    this.initMapCallback = initMapCallback; // 初始化地图回调函数
    this.onClickPoint = onClickPoint; // 点击地图回调函数
    this.onClickArea = onClickArea; // 点击区域回调函数

    this.innerImageryLayerDataSource = new Map(); // 内部数据源 - 图层

    this.innerPointDataSource = new Map(); // 内部数据源 - 内部（撒点）
    this.innerAreaDataSource = new Map(); // 内部数据源 - 内部（区域）
    this.innerCircleDataSource = new Map(); // 内部数据源 - 内部（圈）
  }
  /**
   * 初始化viewer
   */
  initViewer = () => {
    try {
      this.viewer = new Cesium.Viewer(this.dom, {
        // infoBox: false,
        // timeline: false,
        // animation: false,
        // baseLayer: false,
        // shouldAnimate: true,
        // selectionIndicator: false,
        // vrButton: false, // VR
        // geocoder: false, // 位置查找工具
        // homeButton: false, // 视角返回初始位置
        // sceneModePicker: false, // 选择视角的模式（球体、平铺、斜视平铺）
        // baseLayerPicker: false, // 图层选择器（地形影像服务）
        // fullscreenButton: false, // 全屏
        // navigationHelpButton: false, // 导航帮助(手势，鼠标)
        // contextOptions: {
        //   webgl: {
        //     alpha: true,
        //     depth: false,
        //     stencil: true,
        //     antialias: true,
        //     premultipliedAlpha: true,
        //     failIfMajorPerformanceCaveat: false,
        //   },
        //   allowTextureFilterAnisotropic: true,
        // },
      });
      // 关闭太阳，月亮，天空盒，雾等相关特效
      // this.viewer.scene.moon.show = false;
      // this.viewer.scene.fog.enabled = false;
      // this.viewer.scene.sun.show = false;
      // this.viewer.scene.skyBox.show = false;
    } catch (error) {
      console.warn(error);
    }
  };
  /**
   * 通过目标的位置，计算相机的位置
   * @param targetPosition 目标位置
   */
  flyToPositionByTargetLngLatHeight = (targetPosition: IPositionLngLatHeight) => {
    try {
      if (this.viewer) {
        const scene = this.viewer.scene;
        const canvas = this.viewer.canvas;
        const currentCamera = this.viewer.camera;
        const globe = scene.globe;
        const screenCenter = new Cesium.Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 2);
        const ray = currentCamera.getPickRay(screenCenter);
        if (ray) {
          const cartesian = globe.pick(ray, scene);
          if (cartesian) {
            const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
            const longitude = Cesium.Math.toDegrees(cartographic.longitude);
            const latitude = Cesium.Math.toDegrees(cartographic.latitude);
            const height = cartographic.height;
            const currentTarget = Cesium.Cartesian3.fromDegrees(longitude, latitude, height);
            const subtract = Cesium.Cartesian3.subtract(currentCamera.position, currentTarget, new Cesium.Cartesian3());
            const nextTarget = Cesium.Cartesian3.fromDegrees(
              targetPosition.lng,
              targetPosition.lat,
              targetPosition.height || 0,
            );
            const nextCamera = Cesium.Cartesian3.add(nextTarget, subtract, new Cesium.Cartesian3());
            this.viewer.camera.flyTo({
              destination: nextCamera,
              orientation: {
                heading: currentCamera.heading,
                pitch: currentCamera.pitch,
                roll: currentCamera.roll,
              },
            });
          }
        }
      }
    } catch (error) {
      console.warn(error);
    } finally {
      console.error('目标的经纬度', targetPosition);
    }
  };
  /**
   * 设置相机位置
   * @param target 目标位置
   * @param cameraOrientation 相机朝向
   * @param distance 相机距离
   */
  setCameraPositionByTargetLngLatHeight = (
    target: IPositionLngLatHeight,
    cameraOrientation: ICameraOrientation = {},
    distance: number = 1000,
  ) => {
    try {
      if (this.viewer) {
        const headingRadians = Cesium.Math.toRadians(cameraOrientation.heading || 0); // 摄像机航向（度转弧度）
        const pitchRadians = Cesium.Math.toRadians(cameraOrientation.pitch || -45); // 摄像机俯仰（度转弧度）
        const rollRadians = Cesium.Math.toRadians(cameraOrientation.roll || 0); // 摄像机滚转（度转弧度）
        const targetPosition = Cesium.Cartesian3.fromDegrees(target.lng, target.lat, target.height || 0);
        // 2. 计算摄像机的位置
        const direction = new Cesium.Cartesian3(0, 0, -1); // 指向负Z轴
        const orientation = new Cesium.HeadingPitchRoll(headingRadians, pitchRadians, rollRadians);
        // 创建一个表示摄像机朝向的变换矩阵
        const orientationMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(targetPosition, orientation);

        // 3. 计算变换后的方向向量
        const transformedDirection = Cesium.Matrix3.multiplyByVector(
          orientationMatrix,
          direction,
          new Cesium.Cartesian3(),
        );
        // 4. 计算摄像机的位置
        const cameraPosition = Cesium.Cartesian3.add(
          targetPosition,
          Cesium.Cartesian3.multiplyByScalar(transformedDirection, distance, new Cesium.Cartesian3()),
          new Cesium.Cartesian3(),
        );

        this.viewer.camera.setView({
          destination: cameraPosition,
          orientation: {
            heading: headingRadians,
            pitch: pitchRadians,
            roll: rollRadians,
          },
        });
      }
    } catch (error) {
      console.warn(error);
    }
  };
  /**
   * 重置鼠标事件
   */
  resetMouseActions = () => {
    try {
      if (this.viewer) {
        const scene = this.viewer.scene;
        const camera = this.viewer.camera;
        const handler = new Cesium.ScreenSpaceEventHandler(this.viewer.canvas);
        this.viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
        this.viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(
          Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK,
        );
        this.viewer.scene.screenSpaceCameraController.zoomEventTypes = [
          Cesium.CameraEventType.WHEEL,
          Cesium.CameraEventType.PINCH,
        ];
        this.viewer.scene.screenSpaceCameraController.tiltEventTypes = [
          Cesium.CameraEventType.PINCH,
          Cesium.CameraEventType.RIGHT_DRAG,
        ];
        handler.setInputAction((movement: Cesium.ScreenSpaceEventHandler.PositionedEvent) => {
          const position = movement.position;
          const pickRay = camera.getPickRay(position);
          if (!pickRay) {
            return;
          }
          const intersection = scene.globe.pick(pickRay, scene);
          if (!Cesium.defined(intersection)) {
            return;
          }
          const cartographic = Cesium.Cartographic.fromCartesian(intersection);
          const longitude = Cesium.Math.toDegrees(cartographic.longitude);
          const latitude = Cesium.Math.toDegrees(cartographic.latitude);
          this.flyToPositionByTargetLngLatHeight({ lng: longitude, lat: latitude, height: 0 });
        }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
        handler.setInputAction((movement: Cesium.ScreenSpaceEventHandler.PositionedEvent) => {
          // const pickedObject = this.viewer.scene.pick(movement.position);
          // if (pickedObject && pickedObject.id) {
          //   if (pickedObject.primitive instanceof Cesium.Primitive) {
          //     if (lodash.isArray(pickedObject.id)) {
          //       const targets = pickedObject.id.map((item) => {
          //         return getEntityProperties(item);
          //       });
          //       this.onClickArea && this.onClickArea(targets);
          //     } else {
          //       // 点击单个点
          //       const properties = getEntityProperties(pickedObject.id);
          //       this.onClickArea && this.onClickArea(properties);
          //     }
          //   } else if (pickedObject.primitive instanceof Cesium.Billboard) {
          //     if (lodash.isArray(pickedObject.id)) {
          //       const targets = pickedObject.id.map((item) => {
          //         return getEntityProperties(item);
          //       });
          //       this.onClickPoint && this.onClickPoint(targets);
          //     } else {
          //       // 点击单个点
          //       const properties = getEntityProperties(pickedObject.id);
          //       this.onClickPoint && this.onClickPoint(properties);
          //     }
          //   }
          // }
        }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
      }
    } catch (error) {
      console.warn(error);
    }
  };
  /**
   * 追加 图层
   * @param urlTemplateImageryProviders
   */
  addImageryLayerByUrlTemplateImageryProvider = ({
    key,
    urlTemplateImageryProvider,
  }: {
    key?: string;
    urlTemplateImageryProvider: Cesium.UrlTemplateImageryProvider;
  }) => {
    try {
      if (!this.viewer) {
        return;
      }
      const imageryProvider = new Cesium.UrlTemplateImageryProvider(urlTemplateImageryProvider);

      const imageryLayer = this.viewer?.imageryLayers.addImageryProvider(imageryProvider);
      if (key) {
        this.innerImageryLayerDataSource?.set(key, imageryLayer);
      }
    } catch (error) {
      console.warn(error);
    }
  };
  /**
   * 移除 图层
   * @param key
   */
  removeImageryLayerByUrlTemplateImageryProviderKey = ({ key }: { key: string }) => {
    try {
      if (!this.viewer) {
        return;
      }
      const imageryProvider = this.innerImageryLayerDataSource?.get(key);
      if (imageryProvider) {
        this.viewer.imageryLayers.remove(imageryProvider);
        this.innerImageryLayerDataSource?.delete(key);
      }
    } catch (error) {
      console.warn(error);
    }
  };
  /**
   * 清空 图层
   */
  removeAllImageryLayer = () => {
    try {
      if (!this.viewer) {
        return;
      }
      this.viewer.imageryLayers.removeAll();
      this.innerImageryLayerDataSource?.clear();
    } catch (error) {
      console.warn(error);
    }
  };
  /**
   * 添加3dtileset
   */
  addViewerScenePrimitives3DTileset = async (url: string) => {
    try {
      const tileset = await Cesium.Cesium3DTileset.fromUrl(url);
      this.viewer?.scene.primitives.add(tileset);
    } catch (error) {
      console.warn(error);
    }
  };
  /**
   * 新增区域
   * @param param0
   */
  addArea = async ({ key, source, layout, filter }: IArea) => {
    try {
      const dataSource = await Cesium.GeoJsonDataSource.load(source, {
        clampToGround: true,
      });
      dataSource.name = key;
    } catch (error) {
      console.warn(error);
    }
  };
  /**
   * 画圈
   * @param target
   */
  addCircle = (target: IPositionLngLatHeight, circle: ICircle) => {
    try {
      if (this.viewer) {
        // 创建时指定ID
        const circleEntity = this.viewer.entities.add({
          id: circle.key,
          position: Cesium.Cartesian3.fromDegrees(target.lng, target.lat, target.height || 0),
          ellipse: circle.ellipse,
        });
        this.innerCircleDataSource?.set(circle.key, circleEntity);
      }
    } catch (error) {
      console.warn(error);
    }
  };
  /**
   * 移除圈
   * @param key
   */
  removeCircle = (key: string) => {
    try {
      if (this.viewer) {
        const circleEntity = this.innerCircleDataSource?.get(key);
        if (circleEntity) {
          this.viewer.entities.remove(circleEntity);
          this.innerCircleDataSource?.delete(key);
        }
      }
    } catch (error) {
      console.warn(error);
    }
  };
}
